﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bat_sym.Models;
using System.Windows;

namespace bat_sym.SimulationLogic.Rules
{
    class Reproduction : ISimulationRule
    {
        private Random _rng;
        public Reproduction(int days)
        {
            RuleName = "Reproduction";
            Parameters.Add("Days to mate", days);

            _rng = new Random();
        }

        public override void Execute(System.Collections.ObjectModel.ObservableCollection<Models.Bat> bats)
        {
            var _days = Parameters["Days to mate"];
            System.Collections.ObjectModel.ObservableCollection<Models.Bat> kids = new System.Collections.ObjectModel.ObservableCollection<Models.Bat>();
            int i = 1;
            lock (bats)
            {
                foreach (Models.Bat bat in bats.Where(bat => bat.alive & bat.DaysParent > _days))
                {
                    bat.DaysParent = 0;

                    if (bats.Where(b => b.alive & b.DaysParent > _days & b.Label != bat.Label).Count() <= 0)
                        break;
                    Models.Bat parent = bats.Where(b => b.alive & b.DaysParent > _days & b.Label != bat.Label).First();
                    i++;
                    parent.DaysParent = 0;

                    if (!bat.Family.Contains(parent))
                    {
                        parent.Family.Add(bat);
                        bat.Family.Add(parent);
                    }
                    Models.Bat kid = new Models.Bat { Behaviour = BatBehaviour.Cooperative, FoodAmmount = 100, Label = "#" + (bats.Count + i).ToString() };
                    if (bat.Behaviour == parent.Behaviour && bat.Behaviour == BatBehaviour.Cheating)
                    {
                        kid.Behaviour = BatBehaviour.Cheating;
                    }
                    else if (bat.Behaviour != parent.Behaviour)
                    {
                        if (_rng.Next() % 2 == 1)
                        {
                            kid.Behaviour = BatBehaviour.Cheating;
                        }
                    }
                    if (!kids.Contains(kid))
                        kids.Add(kid);
                    kid.Family.Add(parent);
                    kid.Family.Add(bat);
                    parent.Family.Add(kid);
                    bat.Family.Add(kid);
                    kid.Age = 0;
                    kid.DaysParent = 0;
                }
            }
            if (kids.Count > 0)
            {
                lock (bats)
                {
                    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        foreach (Models.Bat kid in kids)
                        {
                            bats.Add(kid);
                        }
                    }));
                }
                
            }
        }
    }
}
